﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Foxit.PDF;
using Foxit.PDF.PageElements;
using Foxit.PDF.Imaging;
using Foxit.PDF.Merger;
using Sustainalytics.Reporting.Framework;

namespace Sustainalytics.ReportGenerator.BL
{
    public class TearSheetReportGenerator
    {
        private readonly TearSheetReportDataSource _dataSource;
        private readonly bool _useParallel;
        private PdfReport _pdfReport;

        # region Static Images

        private static byte[] _companyLogoHeaderImage;
        private static byte[] _companyLogoFooterImage;

        public static byte[] CompanyLogoHeaderImage => _companyLogoHeaderImage;
        public static byte[] CompanyLogoFooterImage => _companyLogoFooterImage;

        private static void LoadStaticImages()
        {
            if (_companyLogoHeaderImage == null)
                _companyLogoHeaderImage = ImagesGenerator.GetJpgImage(@"Images\sustaynalytics_logo_header.jpg");

            if (_companyLogoFooterImage == null)
                _companyLogoFooterImage = ImagesGenerator.GetJpgImage(@"Images\sustaynalytics_logo_footer.jpg");
        }

        #endregion

        static TearSheetReportGenerator()
        {
            LoadStaticImages();
        }

        public TearSheetReportGenerator()
        {
        }


        private static void ValidateInput(string name, object obj, Guid id)
        {
            if (obj == null)
                throw new ArgumentException(
                    "CompanyReportDataOffline does not contain the necessary data for report generation: " + name + " " + id);
        }

        public TearSheetReportGenerator(TearSheetReportDataSource dataSource, bool useParallel)
        {
            if (dataSource == null || dataSource.CompanyId == null)
            {
                throw new ArgumentException(
                    "CompanyReportDataOffline does not contain the necessary data for report generation!");
            }

            ValidateInput("CorporateData", dataSource.CorporateData, dataSource.CompanyId);


            _dataSource = dataSource;
            _useParallel = useParallel;
        }

        public byte[] GetPdfDocument()
        {
            _pdfReport = new PdfReport();

            PdfReportSection overviewSection = null;
            PdfReportSection keyIssuesSection = null;
            PdfReportSection controversiesSection = null;
            PdfReportSection productInvolvementSection = null;

            if (_useParallel)
            {
                Parallel.Invoke(
                    () => { overviewSection = GetOverviewSection(); },
                    () => { keyIssuesSection = GetKeyIssuesSection(); },
                    () => { controversiesSection = GetControversiesSection(); },
                    () => { productInvolvementSection = GetProductInvolvementSection(); }
                    );
            }
            else
            {
                overviewSection = GetOverviewSection();
                keyIssuesSection = GetKeyIssuesSection();
                controversiesSection = GetControversiesSection();
                productInvolvementSection = GetProductInvolvementSection();
            }

            ImportPdfDocument(overviewSection);
            ImportPdfDocument(keyIssuesSection);
            ImportPdfDocument(controversiesSection);
            ImportPdfDocument(productInvolvementSection);


            AddPageFooter(_pdfReport);

            return _pdfReport.Draw();
        }

        private void ImportPdfDocument(PdfReportSection section)
        {
            if (section == null || section?.PdfDocument.Length <= 0) return;

            var pageOffset = _pdfReport.PageCounter;

            var pdfDocument = new PdfDocument(section.PdfDocument);

            for (var page = 1; page <= pdfDocument.Pages.Count; page++)
            {
                _pdfReport.AddPage(new ImportedPage(pdfDocument.GetPage(page)));
            }

            if (section.OutlinePositions.Any())
            {
                AddBookmarks(_pdfReport, pageOffset, section.OutlinePositions);
            }
        }


        private static void AddBookmarks(PdfReport report, int pageOffset, IEnumerable<Reporting.Framework.OutlinePosition> outlinePositions)
        {
            foreach (var parentOutlinePosition in outlinePositions)
            {
                var parentOutline = report.ParentOutline.ChildOutlines.Add(parentOutlinePosition.Name,
                    new XYDestination(parentOutlinePosition.PageNumber + pageOffset, 0.0f,
                        parentOutlinePosition.VerticalPosition));

                if (parentOutlinePosition.ChildOutlinePositions == null ||
                    !parentOutlinePosition.ChildOutlinePositions.Any()) continue;

                foreach (var childOutlinePosition in parentOutlinePosition.ChildOutlinePositions)
                {
                    var childOutline = parentOutline.ChildOutlines.Add(childOutlinePosition.Name,
                        new XYDestination(childOutlinePosition.PageNumber + pageOffset, 0,
                            childOutlinePosition.VerticalPosition));

                    if (childOutlinePosition.ChildOutlinePositions == null ||
                    !childOutlinePosition.ChildOutlinePositions.Any()) continue;

                    foreach (var subChildOutlinePosition in childOutlinePosition.ChildOutlinePositions)
                    {
                        childOutline.ChildOutlines.Add(subChildOutlinePosition.Name,
                            new XYDestination(subChildOutlinePosition.PageNumber + pageOffset, 0,
                                subChildOutlinePosition.VerticalPosition));
                    }
                }
            }
        }

 
        private PdfReportSection GetOverviewSection()
        {
            var section = new TearSheetOverviewSection();

            return section.GeneratePdfReportSection(_dataSource);
        }

        private PdfReportSection GetKeyIssuesSection()
        {
            var section = new TearSheetKeyIssuesSection();

            return section.GeneratePdfReportSection(_dataSource);
        }

        private PdfReportSection GetControversiesSection()
        {
            var section = new TearSheetControversiesSection();

            return section.GeneratePdfReportSection(_dataSource);
        }

        private PdfReportSection GetProductInvolvementSection()
        {
            var section = new TearSheetProductInvolvementSection();

            return section.GeneratePdfReportSection(_dataSource);
        }

        private static void AddPageFooter(PdfReport report)
        {
            var pageNumber = 1;
            var pageCount = report.Document.Pages.Count;

            for (var i = 0; i < report.Document.Pages.Count; i++)
            {
                var page = report.Document.Pages[i];

                page.Elements.Add(new Image(ImageData.GetImage(CompanyLogoFooterImage),
                        report.LeftMargin + 125f, 775, 0.35f)
                { Align = Align.Right, VAlign = VAlign.Top });

                page.Elements.Add(new Label($"© {DateTime.UtcNow.Year} Sustainalytics. All rights reserved.",
                    report.LeftMargin, 785, report.PageMaxWidth, 10f, Fonts.CalibriRegular, 8f, TextAlign.Center, RgbColor.DimGray));

                page.Elements.Add(new Label($"Page {pageNumber} of {pageCount}",
                    500f, 785f, 50f, 10f, Fonts.CalibriRegular, 8, TextAlign.Right, RgbColor.DimGray));

                pageNumber++;
            }
        }

    }


}